﻿using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using ZYXmeBase.Data;
using ZYXmeBase.Models;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using ZYXmeBase.Middleware;
using Swashbuckle.AspNetCore.Filters;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Autofac;
using System.Reflection;
using ZYXmeBase.Repositories;

public class Startup
{
    public IConfiguration Configuration { get; }
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyDbContext>(options =>
            options.UseMySql(Configuration.GetConnectionString("DefaultConnection"),
            new MySqlServerVersion(new Version(8, 0, 18))));
        services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<MyDbContext>();

        services.AddControllers();

        //增加AutoMapper
        services.AddAutoMapper(typeof(Startup));
        //...其他代码
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });

            c.OperationFilter<AddResponseHeadersFilter>();
            c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
            c.OperationFilter<SecurityRequirementsOperationFilter>();
            //运行swagger传输token
            //c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
            //{
            //    Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}（注意两者之间是一个空格）\"",
            //    Name = "Authorization",//jwt默认的参数名称
            //    In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
            //    Type = SecuritySchemeType.ApiKey
            //});
            // 添加 JWT 安全定义
            var securitySchema = new OpenApiSecurityScheme
            {
                Description = "JWT授权 (Bearer)",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.Http,
                Scheme = "bearer",
                BearerFormat = "JWT",
                Reference = new OpenApiReference
                {
                    Id = JwtBearerDefaults.AuthenticationScheme,
                    Type = ReferenceType.SecurityScheme
                }
            };

            c.AddSecurityDefinition(securitySchema.Reference.Id, securitySchema);
            c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                { securitySchema, new string[] { } },
            });

        });


        //鉴权 与 中间件app.UseMiddleware<AuthTokenMiddleware>(); 二选一，且此处代码优先级较高
        var jwtSettings = Configuration.GetSection("Jwt");
        var secretKey = jwtSettings.GetSection("SecretKey").Value;
        var issuer = Configuration["Jwt:Issuer"];
        var audience = jwtSettings.GetSection("Audience").Value;

        services.AddAuthentication(auth =>
        {
            auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        })
        .AddJwtBearer(token =>
        {
            token.RequireHttpsMetadata = false;
            token.SaveToken = true;
            token.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey)),
                ValidateIssuer = true,
                ValidIssuer = issuer,
                ValidateAudience = true,
                ValidAudience = audience,
                RequireExpirationTime = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero
            };
            token.Events = new JwtBearerEvents
            {
                OnAuthenticationFailed = context =>
                {
                    context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                    return Task.CompletedTask;
                }
            };
        });

        services.AddControllers(config =>
        {
            var policy = new AuthorizationPolicyBuilder()
                             .RequireAuthenticatedUser()
                             .Build();
            config.Filters.Add(new AuthorizeFilter(policy));
        });

        services.AddAuthorization();


        //依赖注入注册

    }

    // 这个方法允许你使用 Autofac 容器
    public void ConfigureContainer(ContainerBuilder builder)
    {
        builder.RegisterType<MyDbContext>()
            .As<DbContext>()
            .InstancePerLifetimeScope();
        // 自动生成注册服务
        var dataAccess = Assembly.GetExecutingAssembly();
        builder.RegisterAssemblyTypes(dataAccess)
            .Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository"))
            .AsImplementedInterfaces();

        // 通用注册 IRepository<TEntity, TKey> 的实现 Repository<TEntity, TKey>
        builder.RegisterGeneric(typeof(Repository<,>))
            .As(typeof(IRepository<,>))
            .InstancePerDependency();

    }



    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
    {
        //...中间件配置
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

        //异常处理中间件
        app.UseMiddleware<ExceptionMiddleware>();
        app.UseDeveloperExceptionPage();

        //顺序有要求，需要先注册Swagger，再注册权限，不然无法匿名访问swagger
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
            c.RoutePrefix = string.Empty;    //将 RoutePrefix 设置为空字符串，这能确保应用运行时会自动打开 Swagger UI。
        });

        //鉴权中间件
        app.UseMiddleware<AuthTokenMiddleware>();
        //已由鉴权中间件处理，可以理解为处理鉴权后的中间件
        app.UseMiddleware<MyAuthenticationMiddleware>();


        //swagger
        // 在 UseRouting 和 UseAuthorization 之后，将 Swagger 中间件和 UI 配置为在 pipeline 中执行：


    }
}
